package com.mby.utils;

import com.mby.entity.BaseModel;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 数据库支持方法工具类
 * Created by noah on 2017/8/14.
 */

@Service
public class MongoUtil {

    /**
     * 根据json字符串获取更新内容
     * @param update_str
     * @return Update
     */
    public static Update getUpdate(String update_str){
        Update update = new Update();
        SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String key;Object value;int count = 0;
        try{
            JSONObject jb = JSONObject.fromObject(update_str);
            Iterator it = jb.keys();
            while (it.hasNext()) {
                key = (String) it.next();
                value = jb.get(key);
                if(key.contains("+")){ //加
                    key = key.replace("+","");
                    if(value.toString().contains(".")){ //小数
                        update.inc(key,Double.parseDouble(value.toString()));
                    }else{
                        update.inc(key,Integer.parseInt(value.toString()));
                    }
                }else {
                    if (value.equals("null") || value == null || "\"null\"".equals(value)) {
                        if (count == 0) {
                            update = Update.update(key, null);
                        }else{
                            update.set(key, null);
                        }
                    }else{
                        if (count == 0) {
                            if(isValidDate(value.toString())){  //日期
                                update = Update.update(key, format.parse(value.toString()));
                            }else{
                                update = Update.update(key, value);
                            }
                        } else {
                            if(isValidDate(value.toString())){  //日期
                                update.set(key, format.parse(value.toString()));
                            }else{
                                update.set(key, value);
                            }
                        }
                    }
                }
                count++;
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return update;
    }

    /**
     * 根据json字符串获取查询条件和排序条件
     * @param where_str
     * @param sort_str
     * @param inc_str
     * @return Query
     */
    public static Query getQuery(String where_str, String sort_str, String inc_str){
        Query query = new Query();
        Criteria criteria = null;
        int limit = 0;
        Map<String,Object> map = new HashMap<>();
        SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String temp_key,key;Object value;
        Collection in = new Vector<>();
        try{
            //处理条件字段
            if(where_str == null || "".equals(where_str)){

            }else{
                JSONObject jb = JSONObject.fromObject(where_str);
                Iterator it = jb.keys();
                while (it.hasNext()) {
                    temp_key = (String) it.next();
                    key = temp_key.replace("<","").replace(">","").replace("=","").replace("!","").replace("#","").replace("*","");
                    value = jb.get(temp_key);
                    if(map.containsKey(key)){
                        if(temp_key.contains("<")){
                            criteria = (Criteria) map.get(key);
                            if(temp_key.contains("=")){
                                if(isValidDate(value.toString())){
                                    criteria = criteria.lte(format.parse(value.toString()));
                                }else{
                                    criteria = criteria.lte(value);
                                }
                            }else{
                                if(isValidDate(value.toString())){
                                    criteria = criteria.lt(format.parse(value.toString()));
                                }else{
                                    criteria = criteria.lt(value);
                                }
                            }
                        }
                        map.put(key,criteria);
                    }else{
                        if(temp_key.contains(">")){
                            if(temp_key.contains("=")){
                                if(isValidDate(value.toString())){
                                    criteria = Criteria.where(key).gte(format.parse(value.toString()));
                                }else{
                                    criteria = Criteria.where(key).gte(value);
                                }
                            }else{
                                if(isValidDate(value.toString())){
                                    criteria = Criteria.where(key).gt(format.parse(value.toString()));
                                }else{
                                    criteria = Criteria.where(key).gt(value);
                                }
                            }
                        }else if(temp_key.contains("<")){
                            if(temp_key.contains("=")){
                                if(isValidDate(value.toString())){
                                    criteria = Criteria.where(key).lte(format.parse(value.toString()));
                                }else{
                                    criteria = Criteria.where(key).lte(value);
                                }
                            }else{
                                if(isValidDate(value.toString())){
                                    criteria = Criteria.where(key).lt(format.parse(value.toString()));
                                }else{
                                    criteria = Criteria.where(key).lt(value);
                                }
                            }
                        }else if(temp_key.contains("!")){
                            if(isValidDate(value.toString())){
                                criteria = Criteria.where(key).ne(format.parse(value.toString()));
                            }else{
                                if(value instanceof JSONNull){
                                    criteria = Criteria.where(key).ne(null);
                                }else{
                                    criteria = Criteria.where(key).ne(value);
                                }
                            }
                        }else if(temp_key.contains("#")){
                            if(value != null && !"".equals(value)){
                                String[] a = value.toString().split(",");
                                for(int i=0;i<a.length;i++){
                                    if(isInteger(a[i])){
                                        in.add(Integer.parseInt(a[i]));
                                    }else{
                                        in.add(a[i]);
                                    }
                                }
                                criteria = Criteria.where(key).in(in);
                            }else{
                                in.add("");
                                criteria = Criteria.where(key).in(in);
                            }
                        }else if(temp_key.contains("*")){
                            criteria = Criteria.where(key).regex(".*?" +value+ ".*");
                        }else{
                            if("last_id".equals(key)){ //last_id 大于 id
                                criteria = Criteria.where("id").gt(value);
                                limit = 10;
                            }else{
                                if(isValidDate(value.toString())){
                                    criteria = Criteria.where(key).is(format.parse(value.toString()));
                                }else{
                                    if(value instanceof JSONNull){
                                        criteria = Criteria.where(key).is(null);
                                    }else{
                                        criteria = Criteria.where(key).is(value);
                                    }
                                }
                            }
                        }
                        if(criteria != null){
                            map.put(key,criteria);
                        }
                    }
                }
            }


            for (Map.Entry<String, Object> entry : map.entrySet()) {
                query.addCriteria((Criteria) entry.getValue());
            }

            //处理排序字段
            if(sort_str != null && sort_str != ""){
                String[] sortList = sort_str.replace(" ","").replace("desc","").split(",");
                if(sortList.length > 0){
                    if(sort_str.contains("desc")){
                        for(int i=0;i<sortList.length;i++){
                            query.with(new Sort(Sort.Direction.DESC, sortList[i]));
                        }
                    }else{
                        for(int i=0;i<sortList.length;i++){
                            query.with(new Sort(Sort.Direction.ASC, sortList[i]));
                        }
                    }
                }
            }

            //处理只需要返回的字段
            if(inc_str != null && inc_str != ""){
                String[] incList = inc_str.split(",");
                if(incList.length > 0){
                    for(int i=0;i<incList.length;i++){
                        query.fields().include(incList[i]);
                    }
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }

        if(limit > 0){
            query.limit(limit);
        }

        return query;
    }

    /**
     * 判断是否为整数
     * @param str
     * @return
     */
    public static boolean isInteger(String str) {
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(str).matches();
    }

    /**
     * 根据实体类获取更新内容
     * 只取不为null的字段作为更新内容
     * @param model
     * @return Update
     */
    public static Update getUpdateByModel(Object model){
        Update update = new Update();
        int count = 0;
        Class<?> cls = model.getClass();
        Method[] methods = cls.getDeclaredMethods();
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            try {
                String fieldGetName = parGetName(field.getName());
                if (!checkGetMet(methods, fieldGetName)) {
                    continue;
                }
                Method fieldGetMet = cls.getMethod(fieldGetName, new Class[]{});
                Object fieldVal = fieldGetMet.invoke(model, new Object[]{});
                if (fieldVal != null) {
                    if (count == 0) {
                        update = Update.update(field.getName(), fieldVal);
                    } else {
                        update.set(field.getName(), fieldVal);
                    }
                    count++;
                }
            } catch (Exception e) {
                continue;
            }
        }
        return update;
    }

    /**
     * 根据实体类获取查询条件
     * 只取不为null的字段作为条件
     * @param model
     * @param sort_str
     * @param inc_str
     * @return Query
     */
    public static Query getQuery(Object model, String sort_str, String inc_str){
        Query query = new Query();
        Criteria criteria = null;
        Class<?> cls = model.getClass();
        Integer limit = 0;
        Integer lastId = null;
        //遍历实体类自己所有的属性
        Method[] methods = cls.getDeclaredMethods();
        Field[] fields = cls.getDeclaredFields();
        SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Field field : fields) {
            try {
                String fieldGetName = parGetName(field.getName());
                if (!checkGetMet(methods, fieldGetName)) {
                    continue;
                }
                Method fieldGetMet = cls.getMethod(fieldGetName, new Class[]{});
                Object fieldVal = fieldGetMet.invoke(model, new Object[]{});
                if (fieldVal != null) {
                    if("like_str".equals(field.getName())){ //模糊匹配字段
                        criteria = Criteria.where(field.getName()).regex(".?" +fieldVal.toString()+ ".");
                    }else{
                        if(isValidDate(fieldVal.toString())){
                            criteria = Criteria.where(field.getName()).is(format.parse(fieldVal.toString()));
                        }else{
                            criteria = Criteria.where(field.getName()).is(fieldVal);
                        }
                    }
                    query.addCriteria(criteria);
                }
            } catch (Exception e) {
                continue;
            }
        }

        //遍历公共实体类自己所有的属性
        Method[] base_methods = BaseModel.class.getDeclaredMethods();
        Field[] base_fields = BaseModel.class.getDeclaredFields();
        for (Field field : base_fields) {
            try {
                String fieldGetName = parGetName(field.getName());
                if (!checkGetMet(base_methods, fieldGetName)) {
                    continue;
                }
                Method fieldGetMet = BaseModel.class.getMethod(fieldGetName, new Class[]{});
                Object fieldVal = fieldGetMet.invoke(model, new Object[]{});
                if (fieldVal != null) {
                    //last_id 大于 id
                    if("lastId".equals(field.getName())){
                        criteria = Criteria.where("id").gt(fieldVal);
                        lastId = (Integer) fieldVal;
                    }else if("limit".equals(field.getName())){
                        limit = (Integer) fieldVal;
                    }else{
                        if(isValidDate(fieldVal.toString())){
                            criteria = Criteria.where(field.getName()).is(format.parse(fieldVal.toString()));
                        }else{
                            criteria = Criteria.where(field.getName()).is(fieldVal);
                        }
                    }
                    query.addCriteria(criteria);
                }
            } catch (Exception e) {
                continue;
            }
        }

        //处理排序字段
        if(sort_str != null && sort_str != ""){
            String[] sortList = sort_str.replace(" ","").replace("desc","").split(",");
            if(sortList.length > 0){
                if(sort_str.contains("desc")){
                    for(int i=0;i<sortList.length;i++){
                        query.with(new Sort(Sort.Direction.DESC, sortList[i]));
                    }
                }else{
                    for(int i=0;i<sortList.length;i++){
                        query.with(new Sort(Sort.Direction.ASC, sortList[i]));
                    }
                }
            }
        }

        //处理只需要返回的字段
        if(inc_str != null && inc_str != ""){
            String[] incList = inc_str.split(",");
            if(incList.length > 0){
                for(int i=0;i<incList.length;i++){
                    query.fields().include(incList[i]);
                }
            }
        }

        if(lastId != null){
            if(limit == 0){
                limit = 10;
            }
        }

        if(limit > 0){
            query.limit(limit);
        }
        return query;
    }

    /**
     * 根据实体类获取查询条件
     * 只取不为null的字段作为条件
     * @param sort_str
     * @return Query
     */
    public static Query getQueryInIds(Collection<Integer> c, String sort_str, String inc_str){
        Query query = new Query();
        Criteria criteria = Criteria.where("id").in(c);
        query.addCriteria(criteria);

        //处理排序字段
        if(sort_str != null && sort_str != ""){
            String[] sortList = sort_str.replace(" ","").replace("desc","").split(",");
            if(sortList.length > 0){
                if(sort_str.contains("desc")){
                    for(int i=0;i<sortList.length;i++){
                        query.with(new Sort(Sort.Direction.DESC, sortList[i]));
                    }
                }else{
                    for(int i=0;i<sortList.length;i++){
                        query.with(new Sort(Sort.Direction.ASC, sortList[i]));
                    }
                }
            }
        }

        //处理只需要返回的字段
        if(inc_str != null && inc_str != ""){
            String[] incList = inc_str.split(",");
            if(incList.length > 0){
                for(int i=0;i<incList.length;i++){
                    query.fields().include(incList[i]);
                }
            }
        }
        return query;
    }



    /**
     * 判断某个字符串是不是日期格式
     * @param str
     * @return boolean
     */
    public static boolean isValidDate(String str) {
        boolean convertSuccess=true;
        SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            format.setLenient(false);
            format.parse(str);
        } catch (Exception e) {
            convertSuccess=false;
        }
        return convertSuccess;
    }

    /**
     * 判断是否存在某属性的get方法
     * @param methods
     * @param fieldGetMet
     * @return boolean
     */
    public static boolean checkGetMet(Method[] methods, String fieldGetMet) {
        for (Method met : methods) {
            if (fieldGetMet.equals(met.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 拼接某属性的get方法
     * @param fieldName
     * @return String
     */
    public static String parGetName(String fieldName) {
        if (null == fieldName || "".equals(fieldName)) {
            return null;
        }
        int startIndex = 0;
        if (fieldName.charAt(0) == '_')
            startIndex = 1;
        return "get" + fieldName.substring(startIndex, startIndex + 1).toUpperCase() + fieldName.substring(startIndex + 1);
    }
}
